package io.hellsinger.vortex.data.model

import android.os.Parcel
import android.os.Parcelable
import io.hellsinger.filesystem.attribute.DefaultPathAttribute
import io.hellsinger.filesystem.attribute.PathAttribute
import io.hellsinger.filesystem.attribute.PathType
import io.hellsinger.filesystem.attribute.mimetype.DefaultMimeTypeDescriptor
import io.hellsinger.filesystem.attribute.mimetype.MimeType
import io.hellsinger.filesystem.attribute.time.PathTime
import io.hellsinger.filesystem.path.EmptyPath
import io.hellsinger.filesystem.path.Path
import io.hellsinger.filesystem.path.PathOwner
import io.hellsinger.theme.vortex.VortexSettings
import io.hellsinger.vortex.data.parsePath
import io.hellsinger.vortex.data.repository.AndroidStorageRepository
import kotlinx.coroutines.Deferred
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parceler
import kotlinx.parcelize.Parcelize
import kotlinx.parcelize.WriteWith

@Parcelize
class PathItem(
    override val path: @WriteWith<PathParceler> Path,
    val attrs: @WriteWith<PathAttributeParceler> PathAttribute = DefaultPathAttribute(),
) : PathOwner<Path>,
    Parcelable {
    constructor(
        path: String,
        attrs: PathAttribute = DefaultPathAttribute(),
    ) : this(path = parsePath(path = path.encodeToByteArray()), attrs = attrs)

    constructor(
        owner: PathOwner<Path>,
        attrs: PathAttribute = DefaultPathAttribute(),
    ) : this(path = owner.path, attrs = attrs)

    @IgnoredOnParcel
    var description: Deferred<String>? = null

    val id: Long
        get() = attrs.id

    val mime: MimeType
        get() = DefaultMimeTypeDescriptor.describe(path)

    val scheme: Int
        get() = path.scheme

    val parent: PathItem?
        get() = path.parent?.let(::PathItem)

    val type: PathType
        get() = attrs.type

    val isHidden: Boolean
        get() = path.isHidden

    val isPathAbsolute: Boolean
        get() = path.isAbsolute

    val isDirectory: Boolean
        get() = type == PathType.Directory

    val isFile: Boolean
        get() = type == PathType.File

    val creationTime: PathTime
        get() = attrs.creationTime

    val lastAccessTime: PathTime
        get() = attrs.lastAccessTime

    val lastModifiedTime: PathTime
        get() = attrs.lastModifiedTime

    val permission: String
        get() = attrs.permission

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other is Path) return other == path
        if (javaClass != other?.javaClass) return false

        other as PathItem

        return path == other.path
    }

    override fun hashCode(): Int {
        val result = path.hashCode()
        return result
    }
}

object PathParceler : Parceler<Path> {
    override fun create(parcel: Parcel): Path {
        val scheme = parcel.readInt()
        val path = ByteArray(parcel.readInt())
        parcel.readByteArray(path)

        if (path.isEmpty()) return EmptyPath()
        return parsePath(scheme, path)
    }

    override fun Path.write(
        parcel: Parcel,
        flags: Int,
    ) {
        parcel.writeInt(scheme)
        parcel.writeInt(bytes.size)
        parcel.writeByteArray(bytes)
    }
}

object PathTypeParceler : Parceler<PathType> {
    override fun create(parcel: Parcel): PathType = PathType(parcel.readInt())

    override fun PathType.write(
        parcel: Parcel,
        flags: Int,
    ) = parcel.writeInt(original)
}

private object PathAttributeParceler : Parceler<PathAttribute> {
    override fun create(parcel: Parcel): PathAttribute {
        val id = parcel.readLong()
        val type = parcel.readInt()
        val createTimeSecond = parcel.readLong()
        val createTimeNano = parcel.readLong()
        val lastAccessSecond = parcel.readLong()
        val lastAccessNano = parcel.readLong()
        val lastModifiedSecond = parcel.readLong()
        val lastModifiedNano = parcel.readLong()
        val size = parcel.readLong()
        val perm = parcel.readString() ?: "------"

        return object : PathAttribute {
            override val id: Long = id
            override val type: PathType = PathType(type)
            override val size: Long = size
            override val creationTime: PathTime = PathTime(createTimeSecond, createTimeNano)
            override val lastAccessTime: PathTime = PathTime(lastAccessSecond, lastAccessNano)
            override val lastModifiedTime: PathTime = PathTime(lastModifiedSecond, lastModifiedNano)
            override val permission: String = perm
        }
    }

    override fun PathAttribute.write(
        parcel: Parcel,
        flags: Int,
    ) {
        parcel.writeLong(id)
        parcel.writeInt(type.original)
        parcel.writeLong(creationTime.seconds)
        parcel.writeLong(creationTime.nanos)
        parcel.writeLong(lastAccessTime.seconds)
        parcel.writeLong(lastAccessTime.nanos)
        parcel.writeLong(lastModifiedTime.seconds)
        parcel.writeLong(lastModifiedTime.nanos)
        parcel.writeLong(size)
        parcel.writeString(permission)
    }
}

val PathItem.name: String
    get() =
        if (path == AndroidStorageRepository.EXTERNAL_STORAGE_PATH) {
            VortexSettings.texts { key_storage_path_item_name_external_storage }
        } else {
            path.getNameAt().toString()
        }
